/*
 * comlan
 */

package com.promfy.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;

public class FileUtil {
	/**
	 * copy files, contains file and directory.
	 *  
	 * @param url1
	 * @param url2
	 * @throws IOException
	 */
	public static void copyFiles(String url1, String url2) throws IOException {
		File f = new File(url1);
		if(!f.exists()) return;
		(new File(url2)).mkdirs();

		File[] file = (new File(url1)).listFiles();
		if(file == null) return;
		for (int i = 0; i < file.length; i++) {
			if (file[i].isFile()) {

				copyFile(file[i], new File(url2 + file[i].getName()));
			}
			if (file[i].isDirectory()) {

				String sourceDir = url1 + File.separator + file[i].getName();
				String targetDir = url2 + File.separator + file[i].getName();
				copyDirectiory(sourceDir, targetDir);
			}
		}
	}

	/**
	 * copy files, contains file and directory.
	 * 
	 * @param url1
	 * @param url2
	 * @param string 
	 * @throws IOException
	 */
	public static void copyFileToFile(String url1, String url2Path, String url2Name) throws IOException {
		

		File file = new File(url1);
		if(file == null) return;
		File file2 = new File(url2Path);
		if(!file2.exists()) file2.mkdirs();
		copyFile(file, new File(url2Path + url2Name));
	}
	/**
	 * copy file.
	 * 
	 * @param sourceFile
	 * @param targetFile
	 * @throws IOException
	 */
	public static void copyFile(File sourceFile, File targetFile) throws IOException {

		FileInputStream input = null;
		BufferedInputStream inBuff = null;

		FileOutputStream output = null;
		BufferedOutputStream outBuff = null;
		try {
			input = new FileInputStream(sourceFile);
			inBuff = new BufferedInputStream(input);

			output = new FileOutputStream(targetFile);
			outBuff = new BufferedOutputStream(output); 

			byte[] b = new byte[1024 * 5];
			int len;
			while ((len = inBuff.read(b)) != -1) {
				outBuff.write(b, 0, len);
			}
			outBuff.flush();
			output.flush();
		} catch (Exception e) { 
			e.printStackTrace();
		} finally {
			try {
				if (outBuff != null) {
					outBuff.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
				outBuff = null;
			}
			try {
				if (output != null) {
					output.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
				output = null;
			}
			try {
				if (inBuff != null) {
					inBuff.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
				inBuff = null;
			}
			try {
				if (input != null) {
					input.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
				input = null;
			}
		}
	}

	/**
	 * copy directory.
	 * 
	 * @param sourceDir
	 * @param targetDir
	 * @throws IOException
	 */
	public static void copyDirectiory(String sourceDir, String targetDir) throws IOException {

		(new File(targetDir)).mkdirs();

		File[] file = (new File(sourceDir)).listFiles();
		for (int i = 0; i < file.length; i++) {
			if (file[i].isFile()) {

				File sourceFile = file[i];

				File targetFile = new File(new File(targetDir).getAbsolutePath() + File.separator + file[i].getName());
				copyFile(sourceFile, targetFile);
			}
			if (file[i].isDirectory()) {

				String dir1 = sourceDir + "/" + file[i].getName();

				String dir2 = targetDir + "/" + file[i].getName();
				copyDirectiory(dir1, dir2);
			}
		}
	}

	/**
	 * delete files, contains file and directory.
	 * 
	 * @param path
	 */
	public static void deleteFiles(String path) throws Exception{
		File f = new File(path);
		if (!f.exists()) {
			return;
		}
		if (f.delete()) {
			// System.out.println("delete directory : " + f.getAbsolutePath());
		} else {
			File[] fs = f.listFiles();
			for (int i = 0; i < fs.length; i++) {
				if (fs[i].isDirectory()) {
					if (!fs[i].delete()) {
						deleteFiles(fs[i].getAbsolutePath());
					} else {
						// System.out.println("delete directory : " +
						// fs[i].getAbsolutePath());
					}
				} else {
					fs[i].delete();
					// System.out.println("delete file : " +
					// fs[i].getAbsolutePath());
				}
			}
			f.delete();
			// System.out.println("delete directory : " + f.getAbsolutePath());
		}
	}
	
	public static String getStringFromFiles(String keyPath) throws Exception {
		FileInputStream inputStream = null;
		BufferedReader reader = null;
		StringBuilder stringBuilder = new StringBuilder();
		try {
			 inputStream = new FileInputStream(keyPath);
			 reader = new BufferedReader(new InputStreamReader(inputStream));
			for (String line = reader.readLine(); line != null; line = reader.readLine()) {
				stringBuilder.append(line + "\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			if(inputStream != null){				
				try {
					inputStream.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return stringBuilder.toString();
	}
	
	public static void writeStringToFile(String str, String fileName){
		BufferedWriter  buff = null;
		try {
			buff = new BufferedWriter(new FileWriter(fileName));  
			for (int i = 0; i < str.length(); i++) {  
			      buff.write(str.charAt(i));  
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(buff != null){
				try {
					buff.close();
				} catch (IOException e) {
					e.printStackTrace();
					buff = null;
				}
			}
		}
	}
	
	
	/************************************************/
	public static class ReadFromFile {
	    /**
	     * 以字节为单位读取文件，常用于读二进制文件，如图片、声音、影像等文件。
	     */
	    public static void readFileByBytes(String fileName) {
	        File file = new File(fileName);
	        InputStream in = null;
	        try {
	            System.out.println("以字节为单位读取文件内容，一次读一个字节：");
	            // 一次读一个字节
	            in = new FileInputStream(file);
	            int tempbyte;
	            while ((tempbyte = in.read()) != -1) {
	                System.out.write(tempbyte);
	            }
	            in.close();
	        } catch (IOException e) {
	            e.printStackTrace();
	            return;
	        }
	        try {
	            System.out.println("以字节为单位读取文件内容，一次读多个字节：");
	            // 一次读多个字节
	            byte[] tempbytes = new byte[100];
	            int byteread = 0;
	            in = new FileInputStream(fileName);
	            ReadFromFile.showAvailableBytes(in);
	            // 读入多个字节到字节数组中，byteread为一次读入的字节数
	            while ((byteread = in.read(tempbytes)) != -1) {
	                System.out.write(tempbytes, 0, byteread);
	            }
	        } catch (Exception e1) {
	            e1.printStackTrace();
	        } finally {
	            if (in != null) {
	                try {
	                    in.close();
	                } catch (IOException e1) {
	                }
	            }
	        }
	    }

	    /**
	     * 以字符为单位读取文件，常用于读文本，数字等类型的文件
	     */
	    public static void readFileByChars(String fileName) {
	        File file = new File(fileName);
	        Reader reader = null;
	        try {
	            System.out.println("以字符为单位读取文件内容，一次读一个字节：");
	            // 一次读一个字符
	            reader = new InputStreamReader(new FileInputStream(file));
	            int tempchar;
	            while ((tempchar = reader.read()) != -1) {
	                // 对于windows下，\r\n这两个字符在一起时，表示一个换行。
	                // 但如果这两个字符分开显示时，会换两次行。
	                // 因此，屏蔽掉\r，或者屏蔽\n。否则，将会多出很多空行。
	                if (((char) tempchar) != '\r') {
	                    System.out.print((char) tempchar);
	                }
	            }
	            reader.close();
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	        try {
	            System.out.println("以字符为单位读取文件内容，一次读多个字节：");
	            // 一次读多个字符
	            char[] tempchars = new char[30];
	            int charread = 0;
	            reader = new InputStreamReader(new FileInputStream(fileName));
	            // 读入多个字符到字符数组中，charread为一次读取字符数
	            while ((charread = reader.read(tempchars)) != -1) {
	                // 同样屏蔽掉\r不显示
	                if ((charread == tempchars.length)
	                        && (tempchars[tempchars.length - 1] != '\r')) {
	                    System.out.print(tempchars);
	                } else {
	                    for (int i = 0; i < charread; i++) {
	                        if (tempchars[i] == '\r') {
	                            continue;
	                        } else {
	                            System.out.print(tempchars[i]);
	                        }
	                    }
	                }
	            }

	        } catch (Exception e1) {
	            e1.printStackTrace();
	        } finally {
	            if (reader != null) {
	                try {
	                    reader.close();
	                } catch (IOException e1) {
	                }
	            }
	        }
	    }

	    /**
	     * 以行为单位读取文件，常用于读面向行的格式化文件
	     */
	    public static void readFileByLines(String fileName) {
	        File file = new File(fileName);
	        BufferedReader reader = null;
	        try {
	            System.out.println("以行为单位读取文件内容，一次读一整行：");
	            reader = new BufferedReader(new FileReader(file));
	            String tempString = null;
	            int line = 1;
	            // 一次读入一行，直到读入null为文件结束
	            while ((tempString = reader.readLine()) != null) {
	                // 显示行号
	                System.out.println("line " + line + ": " + tempString);
	                line++;
	            }
	            reader.close();
	        } catch (IOException e) {
	            e.printStackTrace();
	        } finally {
	            if (reader != null) {
	                try {
	                    reader.close();
	                } catch (IOException e1) {
	                }
	            }
	        }
	    }

	    /**
	     * 随机读取文件内容
	     */
	    public static void readFileByRandomAccess(String fileName) {
	        RandomAccessFile randomFile = null;
	        try {
	            System.out.println("随机读取一段文件内容：");
	            // 打开一个随机访问文件流，按只读方式
	            randomFile = new RandomAccessFile(fileName, "r");
	            // 文件长度，字节数
	            long fileLength = randomFile.length();
	            // 读文件的起始位置
	            int beginIndex = (fileLength > 4) ? 4 : 0;
	            // 将读文件的开始位置移到beginIndex位置。
	            randomFile.seek(beginIndex);
	            byte[] bytes = new byte[10];
	            int byteread = 0;
	            // 一次读10个字节，如果文件内容不足10个字节，则读剩下的字节。
	            // 将一次读取的字节数赋给byteread
	            while ((byteread = randomFile.read(bytes)) != -1) {
	                System.out.write(bytes, 0, byteread);
	            }
	        } catch (IOException e) {
	            e.printStackTrace();
	        } finally {
	            if (randomFile != null) {
	                try {
	                    randomFile.close();
	                } catch (IOException e1) {
	                }
	            }
	        }
	    }

	    /**
	     * 显示输入流中还剩的字节数
	     */
	    private static void showAvailableBytes(InputStream in) {
	        try {
	            System.out.println("当前字节输入流中的字节数为:" + in.available());
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
	    }

	    public static void main(String[] args) {
	        String fileName = "C:/temp/newTemp.txt";
	        ReadFromFile.readFileByBytes(fileName);
	        ReadFromFile.readFileByChars(fileName);
	        ReadFromFile.readFileByLines(fileName);
	        ReadFromFile.readFileByRandomAccess(fileName);
	    }
	}
	
	public static class AppendToFile {
	    /**
	     * A方法追加文件：使用RandomAccessFile
	     */
	    public static void appendMethodA(String fileName, String content) {
	        try {
	            // 打开一个随机访问文件流，按读写方式
	            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
	            // 文件长度，字节数
	            long fileLength = randomFile.length();
	            //将写文件指针移到文件尾。
	            randomFile.seek(fileLength);
	            randomFile.writeBytes(content);
	            randomFile.close();
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
	    }

	    /**
	     * B方法追加文件：使用FileWriter
	     */
	    public static void appendMethodB(String fileName, String content) {
	        try {
	            //打开一个写文件器，构造函数中的第二个参数true表示以追加形式写文件
	            FileWriter writer = new FileWriter(fileName, true);
	            writer.write(content);
	            writer.close();
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
	    }

	    public static void main(String[] args) {
	        String fileName = "C:/temp/newTemp.txt";
	        String content = "new append!";
	        //按方法A追加文件
	        AppendToFile.appendMethodA(fileName, content);
	        AppendToFile.appendMethodA(fileName, "append end. \n");
	        //显示文件内容
	        ReadFromFile.readFileByLines(fileName);
	        //按方法B追加文件
	        AppendToFile.appendMethodB(fileName, content);
	        AppendToFile.appendMethodB(fileName, "append end. \n");
	        //显示文件内容
	        ReadFromFile.readFileByLines(fileName);
	    }
	}
}
